iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 2
0
自我挑戰組

花式PHP系列 第 2

我來、我見、我宣告變數

  • 分享至 

  • xImage
  •  

先看看這段程式碼:

底下這段程式碼在模擬解析從 Google Distance Matrix API 回傳的結果正不正確、可不可用。
resolveApiResponse 成功的話會回傳一個物件、失敗的話則會回傳 NULL
最後再透過 assertTrue 辨別有沒有執行成功~

底下程式碼的難點都有註記可以參考的網頁

<?php

/*
 * heredoc
 * @see http://php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc
 * 
 * Google Distance Matrix API
 * @see https://developers.google.com/maps/documentation/distance-matrix/start?hl=zh-tw
 */
$data = <<<JSON
{
   "destination_addresses" : [ "New York, NY, USA" ],
   "origin_addresses" : [ "Washington, DC, USA" ],
   "rows" : [
      {
         "elements" : [
            {
               "distance" : {
                  "text" : "225 mi",
                  "value" : 361715
               },
               "duration" : {
                  "text" : "3 hours 49 mins",
                  "value" : 13725
               },
               "status" : "OK"
            }
         ]
      }
   ],
   "status" : "OK"
}
JSON;

/*
 * Return type declarations
 * @see http://php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration
 */
function resolveApiResponse($data): ?stdClass
{
    /*
     * json_decode 會在無法把資料解析成JSON時回傳 NULL
     * @see http://php.net/manual/en/function.json-decode.php
     */
    $response = json_decode($data);
    
    if (is_null($response)) {
        return NULL;
    }
    
    /*
     * 確定API執行成功
     */
    if ($response->status === 'OK' and
        $response->rows[0]->elements[0] and
        $response->rows[0]->elements[0]->status === 'OK'
    ) {
        return $response->rows[0]->elements[0];
    }
    return NULL;
}

/*
 * 只要資料不是 NULL 就能通過測試
 */
function assertTrue($boolean)
{
    echo($boolean ? 'success' : 'fail');
}

assertTrue(resolveApiResponse($data));

有個地方看起來很不順眼...

確定API執行成功」那段:
如果是你,你會怎麼精簡這一段程式碼呢?

<?php

if ($response->status === 'OK' and
    $response->rows[0]->elements[0] and
    $response->rows[0]->elements[0]->status === 'OK'
) {
    return $response->rows[0]->elements[0];
}
return NULL;

把共同的部份提取到 if-else 前面?

<?php

$element = $response->rows[0]->elements[0];

if ($response->status === 'OK' and
    $element and
    $element->status === 'OK'
) {
    return $element;
}
return NULL;

這樣好多了吧?
但我這邊提供給你另外一個作法:

直接在 if-else 裡面宣告!

<?php

if ($response->status === 'OK' and
    $element = $response->rows[0]->elements[0] and
    $element->status === 'OK'
) {
    return $element;
}
return NULL;

這樣子做雖然好像只是節省一行,
但當你在 if-else 之後還有要繼續使用這個變數,
或者你在 if-else 之後還有 n 個變數也需要拿去做額外的處理,這樣的方法就能節省 n 行呢!

另外一個地方也能這麼做

看看最後一行吧!

<?php

assertTrue(resolveApiResponse($data));

我們直接把 resolveApiResponse 回傳的結果丟給 assertTrue 之後,
是不是如果要獲取 API 的結果就只能在 CALL 一次了呢?

不用的!
只要把程式碼改寫成下面這樣就行了!

<?php

assertTrue($response = resolveApiResponse($data));

echo $response->distance->value;

上一篇
Prologue
下一篇
關聯陣列、花式函式宣告與呼叫
系列文
花式PHP31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言